package com.example.bookmanagementsystem.config;

import com.example.bookmanagementsystem.entity.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {

    @Autowired
    private ObjectMapper objectMapper;

    //supports 方法的作用是用来判断是否要拦截和处理某个控制器方法的返回值。
    //Spring 在调用 beforeBodyWrite 之前会先调用 supports，如果 supports 返回 true，则会执行 beforeBodyWrite 进行响应体的处理；如果返回 false，则 beforeBodyWrite 将不会被调用
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        //通过这个检查，可以避免重复包装已经是 Result 类型的响应数据
        if (returnType.getParameterType().equals(Result.class)){
            return false;
        }
        return true;
    }

    //beforeBodyWrite 方法用于在响应体数据写入到 HTTP 响应之前，对其进行最后的修改或包装。
    //例如，统一将所有返回值包装成一个标准格式的对象（比如 Result），以确保 API 返回的数据结构一致。这个方法会在 supports 方法返回 true 的情况下被调用。
    //当方法中抛出受检异常时，通常需要显式捕获或者通过 throws 声明抛出。但使用 @SneakyThrows 后，可以省略这些步骤，Lombok 会在编译时为方法自动添加 throws 逻辑。
    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof String) {
            //如果返回结果为String类型, 使用SpringBoot内置提供的Jackson来实现信息的序列化
            return objectMapper.writeValueAsString(Result.success(body));
        }

        return Result.success(body);
    }
}
